#include "widget.h"
#include "ui_widget.h"
#include "command.h"
#include <QWidget>
#include <QTcpServer>
#include <QNetworkInterface>
#include <QDebug>
#include <QMessageBox>
#include <QTcpSocket>
#include "ui_dialog.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("Modbus TCP slave");
    this->setFixedSize(WINDOW_WIDTH,WINDOW_HEIGHT);
    this->setWindowIcon(QIcon(WINDOWS_ICO_PATH));
    pic.load(BACK_PATH);

    TCPServer = new QTcpServer(this);
    TCPSocket = new QTcpSocket(this);

    //数据初始化
    Initialize();

}

Widget::~Widget()
{
    delete ui;
}

void Widget::Initialize()
{

    ui->slot_disconnect->setEnabled(false);

    if(!QFile::exists("./log.txt"))
    {
        QFile file1("./log.txt");
        file1.open(QIODevice::WriteOnly);
        file1.close();
    }


    connect(ui->SlaveAddr,&QLineEdit::textEdited,[=](){
        if((ui->SlaveAddr->text().toInt()<1)||(ui->SlaveAddr->text().toInt()>127))
        {
            ui->SlaveAddr->clear();
            QMessageBox::critical(this,"提示","从机地址超出范围");
        }
    });


    ui->SlaveAddr->setPlaceholderText("1-247");
    QIntValidator *validator = new QIntValidator(1,247,this);
    ui->SlaveAddr->setValidator(validator);

    SlaveAddressDefault();
    //QFile file("../Modbus-TCP-slave/log.txt");

    settings = new QSettings("../Modbus-TCP-slave/Data/Data.ini",QSettings::IniFormat);

   // connect(ui->messageEdit,SIGNAL(textChanged()),this,SLOT(messageLogging()));

    connect(ui->coilSearchBtn,&QPushButton::clicked,[=](){
        int coilIndex = ui->coilLineEdit->text().toInt(nullptr,10);
        //获取搜索位置的指针
        QTableWidgetItem *coilItem = ui->coilTable->item(0,coilIndex);
        ui->coilTable->setCurrentItem(coilItem);
        //滚动到指向位置
        ui->coilTable->scrollToItem(coilItem,QAbstractItemView::PositionAtCenter);
    });
    connect(ui->registerSearchBtn,&QPushButton::clicked,[=](){
        int coilIndex = (ui->registerLineEdit->text().toInt(nullptr,10));
        //获取搜索位置的指针
        QTableWidgetItem *coilItem = ui->registerTable->item(0,coilIndex);
        ui->registerTable->setCurrentItem(coilItem);
        //滚动到指向位置
        ui->registerTable->scrollToItem(coilItem,QAbstractItemView::PositionAtCenter);
    });


    //    TcpSocket = new QTcpSocket(this);
    QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName()); //从主机名获取IP地址
    //    qDebug()<<"!!!";
    //    QString ip= info.addresses().at(1).toString();      //要把info转换为QString才能把它放到文本框中
    QString ip= QNetworkInterface().allAddresses().at(1).toString();
    qDebug() <<"IP Address: "<<info.addresses();
    //    ui->IPText->setText(QNetworkInterface().allAddresses().at(1).toString());
    ui->lineEditIP->setText(ip);
    ui->lineEditPort->setText("502");
    //ui->IPText->setText(ip);
    ui->state->setText("未有客户端连接");
    this->isconnection=false;

    DisplayDataToList();

    //    ui->LableIP->setVisible(false);

    //字体颜色改变
    QPalette pe;
    pe.setColor(QPalette::WindowText,Qt::white);
    ui->state->setPalette(pe);
    ui->label->setPalette(pe);
    ui->LableIP->setPalette(pe);
    ui->LablePort->setPalette(pe);
    ui->groupBox->setPalette(pe);

}

//初始化从机地址
void Widget::SlaveAddressDefault()
{
    if(ui->SlaveAddr->text().isEmpty())
    {
        SlaveAddress = defaultSlaveAddress;
        ui->SlaveAddr->setText(QString::number(SlaveAddress));
    }
    else
    {
        SlaveAddress = ui->SlaveAddr->text().toInt();
    }
}

//显示请求报文
void Widget::ShowRequestMessage()
{
    //接收字节数组并转化
    QString res;
    TcpRequestMessage =  TCPSocket->readAll();
    res = HexByteArrayToHexString(TcpRequestMessage,TcpRequestMessage.size(),1);
    //显示收到的报文
    timeInformationPrint();
    ui->messageEdit->append("请求报文地址："+ IP + ":"+ Port);
    ui->messageEdit->append("请求报文内容："+res);
}
void Widget::ShowResponseMessage(QByteArray MessageArray)
{
    QString res;
    res = HexByteArrayToHexString(MessageArray,MessageArray.size(),1);
    //显示收到的报文
    //TimeInformation();
    //ui->messageBox->append("请求报文地址："+MasterIpAddress + ":"+QString::number(MasterPortNumber));
    ui->messageEdit->append("响应报文内容："+res);
}

//读取数据到表格
void Widget::DisplayDataToList()
{
    QString readData;
    ui->coilTable->setRowCount(2);
    ui->coilTable->setColumnCount(MAX_NUMBER+1);
    ui->registerTable->setRowCount(2);
    ui->registerTable->setColumnCount(MAX_NUMBER+1);

    for(int i = 0;i<MAX_NUMBER+1 ;i++)
    {
        QString addr =  "0x" + QString("%1").arg(i,4,16,QLatin1Char('0'));

        ui->coilTable->setItem(0,i,new QTableWidgetItem(QString(addr)));
        readData = settings->value("Section" + QString::number(i+1) + "/coil").toString();
        readData=="1"?readData="ON":readData="OFF";
        ui->coilTable->setItem(1,i,new QTableWidgetItem(QString(readData)));

        ui->registerTable->setItem(0,i, new QTableWidgetItem(QString(addr)));
        readData = settings->value("Section" + QString::number(i+1) + "/regi").toString();
        ui->registerTable->setItem(1,i,new QTableWidgetItem(QString(readData)));


        ui->coilTable->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->coilTable->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->registerTable->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->registerTable->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);

    }
    ui->coilTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //ui->registerTable->item(1,i)->setBackground(const QBrush &brush);
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawPixmap(0,0,pic);
}

void Widget::ServerNewConnection()
{
    TCPSocket = TCPServer->nextPendingConnection();  //客户端的连接，获取客户端描述符

    //connect(TCPSocket,SIGNAL(readyRead()),this,SLOT(RecvMessage())); //连接客户端的套接字的有新消息信号到接收消息的槽

    connect(TCPSocket,&QTcpSocket::readyRead,this,[=](){
        //显示接收数据
        ShowRequestMessage();
        messageLogging();
        AnalysisRequestMessage(TcpRequestMessage);

    });

    connect(TCPSocket,SIGNAL(disconnected()),this,SLOT(DisConnect())); //连接客户端的套接字取消连接信号到取消连接槽

    ui->state->setText("有客户端连接");

    ui->slot_disconnect->setEnabled(true);

    TcpServerConnectState = true;

    QMessageBox::information(this, "Modbus TCP slave", "有主机连接！");

    //    qDebug() << "Address:" << TCPSocket->peerAddress ();
    //    qDebug() << "Port:" << TCPSocket->peerPort  ();

    this->isconnection=true;

    IP = TCPSocket->peerAddress().toString();//获取客户端ip
    IP = IP.section(QRegExp("[/:]"),3,3);              //IP地址字符串截取
    quint16 TPort = TCPSocket->peerPort();            //获取客户端端口
    Port = QString::number(TPort);

    //QString IPnumber = IP

    qDebug()<<IP<<":"<<Port;

    //    ui->LableIP->setVisible(true);

    timeInformationPrint();
    //消息窗口显示信息

    QString sendMessage = tr("主站端连接成功!") + tr(" \n") \
            + tr("主站信息为 : ")+ IP + tr(":")+Port+ tr("   \n") ;
    ui->messageEdit->append(sendMessage);

    //    ui->lineEditIP->setText(IP);
    //    ui->lineEditPort->setText(Port);

    ui->slot_disconnect->setEnabled(true);

    //    TCPSocket->close();   //关闭服务器不再监听，直接进入数据收发
}

//0x01功能码 获取线圈数据
QByteArray Widget::GetData0X01(quint16 BeginAddress,quint16 Number)
{
    //声明读取的数据字符串
    QString getDataString;
    quint8 responseMessageByteNum;
    //求响应报文字节数
    responseMessageByteNum = (quint8)((Number + 7) / 8);

    //从数据表中读取需要数量的线圈数据,形成二进制形式字符串
    for(int i = BeginAddress; i < (BeginAddress + Number); i++)
    {
        QString buffer = ui->coilTable->item(1,i)->text();
        if(buffer == "ON")
        {
            getDataString += "1";
        }
        else
        {
            getDataString += "0";
        }
    }

    //二进制字符串补0
    for(int i = 1; i <= (8*responseMessageByteNum - Number); i++)
    {
        getDataString += "0";
    }

    //声明线圈数据数组
    QByteArray coilsDataArr;
    coilsDataArr.resize(responseMessageByteNum);
    //将二进制字符串按字节填入响应报文数组
    for(int i = 0; i < responseMessageByteNum; i++)
    {
        //对8位1字节进行反转处理
        QString buffer = getDataString.mid((8 * i),8);
        //字节反转
        byteReverse(buffer);
        //存入响应报文数组
        coilsDataArr[i] = buffer.toInt(NULL,2);
    }
    return coilsDataArr;

}

//字节翻转函数
void Widget::byteReverse(QString &coils)
{
    // 定义临时字符变量
    QChar temp;
    for(int i=0; i < 4; i++)
    {
        temp = coils[i];        // 将第i个元素存入临时字符变量
        coils[i] = coils[8-i-1];  // 将第i个字符元素和第n-i-1个元素对调
        coils[8-i-1] = temp;    // 将临时字符变量的值赋给第n-i-1个元素
    }
}

//16进制字节数组转化为16进制字符串
QString Widget::HexByteArrayToHexString(QByteArray HexByteArr,int ConvertLen, int pattern = 0)
{
    //获得目标数组大小
    int HexByteArrSize = HexByteArr.size();
    //判断长度是否合法，如果长度大于数组长度，则设为数组长度，小于0则设置为0
    if(ConvertLen > HexByteArrSize)
    {
        ConvertLen = HexByteArrSize;
    }
    else if(ConvertLen < 0)
    {
        ConvertLen = 0;
    }

    //声明目标字符串
    QString readMes = NULL;

    for(int i = 0; i < ConvertLen; i++)
    {
        readMes += QString("%1").arg((quint8)HexByteArr.at(i),2,16,QLatin1Char('0'));
        //判断转换的模式
        if(pattern == 1)
        {
            readMes += " ";
        }
    }

    //返回转化后的十六进制字符串
    return readMes;
}

void Widget::on_Start_clicked()
{
    if(!TCPServer->listen(QHostAddress().Any,quint16(ui->lineEditPort->text().toInt())))
    {
        QMessageBox::information(this, "Modbus TCP slave", "从站端监听启动！");
        ui->Start->setEnabled(false);
        ui->slot_disconnect->setEnabled(false);

        return;
    }
    else
    {
        QMessageBox::information(this, "Modbus TCP slave", "从站端监听启动！");
        ui->Start->setEnabled(false);
        ui->slot_disconnect->setEnabled(false);
        connect(TCPServer, SIGNAL(newConnection()), this, SLOT(ServerNewConnection()));
        return;
    }
}

void Widget::on_Exit_clicked()
{
    QMessageBox::information(this, "Modbus TCP slave", "从站端监听结束！");

    this->close();
}

//接收消息
//void Widget::RecvMessage()
//{

//    if(TCPSocket != nullptr) //与客户端连接的socket，不是nullptr，则说明有客户端存在
//    {
//        QMessageBox::information(this, "Modbus TCP slave", "有新消息！");
//        QByteArray array = TCPSocket->readAll();    //接收消息
//        QHostAddress clientaddr = TCPSocket->peerAddress(); //获得IP
//        int port = TCPSocket->peerPort();   //获得端口号

//        QDateTime datetime = QDateTime::currentDateTime();

//        QString sendMessage = tr("recv from :") + clientaddr.toString() + tr(" : ") \
//                                + QString::number(port) + tr("   \n") + "["+datetime.toString("yyyy-M-dd hh:mm:ss") +"]"+tr("\n");

//        ui->messageEdit->append(sendMessage+QString::fromLocal8Bit(array));   //将接收到的内容加入到listwidget
//    }
//}

//时间信息打印
void Widget::timeInformationPrint()
{
    ui->messageEdit->append("");
    ui->messageEdit->append("[" + QDateTime::currentDateTime().toString("yyyy-M-dd hh:mm:ss") + "]");
}

void Widget::DisConnect()
{
    if(TCPSocket != nullptr && this->isconnection)
    {
        this->isconnection=false;
        ui->messageEdit->append("连接断开!");
        ui->slot_disconnect->setEnabled(false);
        TCPSocket->disconnectFromHost();

        ui->Start->setText("开始监听");

        QMessageBox::information(this, "Modbus TCP slave", "断开与客户端的连接！");



        ui->state->setText("未有客户端连接");

        ui->Start->setEnabled(true);

        }
}

void Widget::solt_SendMessage()
{
    if(this->isconnection)
    {
        QString sendMessage = ui->lineEdit->text(); //从单行文本框获得要发送消息
        if(!sendMessage.isEmpty())
        {
            //发送消息到服务器
            this->TCPSocket->write(sendMessage.toLatin1());
            //            this->TCPSocket->waitForBytesWritten();
            //本地显示发送的消息
            QString localDispalyMessage = tr("send to server: ") + sendMessage \
                    + QDateTime::currentDateTime().toString(" yyyy-M-dd hh:mm:ss") + tr("\n");
            ui->messageEdit->append(localDispalyMessage);
        }
        else
            QMessageBox::warning(this,"错误","消息不能为空!",QMessageBox::Ok);
    }
    else
        QMessageBox::warning(this,"错误","未连接到服务器!",QMessageBox::Ok);

    ui->lineEdit->clear();
}

void Widget::on_pushButton_Sent_clicked()
{
    solt_SendMessage();
}

void Widget::on_pushButton_clicked()
{
    ui->messageEdit->clear();
}

void Widget::on_slot_disconnect_clicked()
{

    this->DisConnect();
}

void Widget::on_viewLog_clicked()
{
    QFile file("./log.txt");

    file.open(QFileDevice::ReadOnly);

    //读取文件
    QByteArray array;
    array = file.readAll();

    dialog = new Dialog(this);
    dialog->setModal(false);

    dialog->ui->textEdit->setText(array);
    //dialog->ui->textEdit->setPlainText(in.readAll().toUtf8());

    dialog->ui->textEdit->moveCursor(QTextCursor::End);

    QApplication::restoreOverrideCursor();
    dialog->show();
}

void Widget::closeEvent(QCloseEvent *event)
{
    QMessageBox::StandardButton result=QMessageBox::question(this, "确认", "确定要退出程序吗？",
                                                             QMessageBox::Yes|QMessageBox::No |QMessageBox::Cancel,
                                                             QMessageBox::No);

    if (result==QMessageBox::Yes)
    {
        messageLogging();

        event->accept();
    }
    else
        event->ignore();
}

//消息日志保存
void Widget::messageLogging()
{
    ui->messageEdit->moveCursor(QTextCursor::End);

    QFile file("./log.txt");
    file.open(QFileDevice::Append);
    file.write(ui->messageEdit->toPlainText().toUtf8().data());
    //消息分块
    file.write("\n\n");
    file.close();
    return ;

}

//解析请求报文
bool Widget::AnalysisRequestMessage(QByteArray MessageArray)
{

    bool AnalysisResult=false;

    //异常判断
    //长度判断：最大长度、最短长度
    if(MessageArray.size() > TCP_MAX_LENGTH)
    {
        ui->messageEdit->append("报文长度错误，报文长度超过最大报文长度！");
        return false;
    }
    if(MessageArray.size() < TCP_MIN_LENGTH)
    {
        ui->messageEdit->append("报文长度错误，报文长度小于最小报文长度！");
        return false;
    }
    //MBAP报文头
    //事务标识符(指定为 00 01)
    quint16 transactionIdentifier;
    transactionIdentifier = BondTwoUint8ToUint16((quint8)MessageArray[0],(quint8)MessageArray[1]);
    if(transactionIdentifier != 1)
    {
        ui->messageEdit->append("事务标识符错误，事务标识符与本机不一致！");
        return false;
    }
    //协议标识符判断
    quint16 protocolNumber;
    protocolNumber = ((quint8)MessageArray[2] << 8) | (quint8)MessageArray[3];
    if(protocolNumber != 0)
    {
        ui->messageEdit->append("报文协议错误，请求报文中报文协议错误！");
        return false;
    }
    //应用数据单元ADU长度判断
    quint16 ADULength;
    ADULength = ((quint8)MessageArray[4] << 8) | (quint8)MessageArray[5];
    if(ADULength != (MessageArray.size()- TCP_MBAP_HEADER_LENGTH))
    {
        ui->messageEdit->append("字节长度错误，请求报文中字节长度与实际应用数据单元长度不一致！");
        return false;
    }
    //从机地址
    quint8 MessageSlaveAddress;
    MessageSlaveAddress = (quint8)MessageArray[6];
    if(SlaveAddress != MessageSlaveAddress)
    {
        ui->messageEdit->append("从机地址错误，请求报文中从机地址与本机从机地址不一致！");
        return false;
    }

    //从机地址(未指定，不判断)
    //功能码判断
    quint8 AbnormalFunctionCode;
    QByteArray AbnormalResponseMessage;
    quint8 FunctionCode;
    FunctionCode = (quint8)MessageArray[7];
    if(FunctionCode != 1 && FunctionCode != 3 && FunctionCode != 15 && FunctionCode != 16)
    {
        //异常报文响应 01
        AbnormalFunctionCode = 0x01;
        AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
        AbnormalMessageSend(AbnormalResponseMessage);
        //异常提示
        ui->messageEdit->append("非法功能码！");
        ShowResponseMessage(AbnormalResponseMessage);
        return false;
    }

    switch (TcpRequestMessage.at(7)) {
    case 1:
        //0x01功能码报文处理函数
        AnalysisResult = AnalysisMessageRead(TcpRequestMessage);
        break;
    case 3:
        //0x03功能码报文处理函数
        AnalysisResult = AnalysisMessageRead(TcpRequestMessage);
        break;
    case 15:
        //0x0f功能码报文处理函数
        AnalysisResult = AnalysisMessageWrite(TcpRequestMessage);
        break;
    case 16:
        //0x10功能码报文处理函数
        AnalysisResult = AnalysisMessageWrite(TcpRequestMessage);
        break;
    }

    if(true == AnalysisResult)
    {
        TcpRequestMessage.clear();
    }
    return AnalysisResult;
}

quint16 Widget::BondTwoUint8ToUint16(quint8 preNum, quint8 afterNum)
{
    quint16 bondNum = (preNum << 8) | afterNum;
    return bondNum;
}

//异常报文生成
QByteArray Widget::AbnormalMessageCreate(QByteArray MessageArray,quint8 AbnormalFunctionCode)
{
    //响应报文总字节数
    quint16 RespondeMessageBytesNum;
    //2+2+2+1+1+1  即事务元标志符+协议标识符+（后续报文）长度+ 地址 + 功能码+异常码
    RespondeMessageBytesNum = 8 + 1;

    QByteArray RespondeMessageArr;
    quint16 length = RespondeMessageBytesNum - 6;
    RespondeMessageArr.resize(RespondeMessageBytesNum);

    //事务元标识符
    RespondeMessageArr[0]=MessageArray[0];
    RespondeMessageArr[1]=MessageArray[1];
    //协议地址
    RespondeMessageArr[2]=MessageArray[2];
    RespondeMessageArr[3]=MessageArray[3];
    //后续包长度
    RespondeMessageArr[4]= length>>8;
    RespondeMessageArr[5]= length & 0xff;
    //地址
    RespondeMessageArr[6]= MessageArray[6];
    //功能码
    quint8 FunctionCode;
    FunctionCode = (quint8)MessageArray[7] +0x80;
    RespondeMessageArr[7]=FunctionCode;
    RespondeMessageArr[8]=AbnormalFunctionCode;

    return RespondeMessageArr;
}

//异常报文发送
void Widget::AbnormalMessageSend(QByteArray Message)
{
    if(TcpServerConnectState)
    {
        TCPSocket->write(Message);
    }
}

//正常报文响应发送
void Widget::NormalResponseMessageSend(QByteArray MessageArray)
{
    if(TcpServerConnectState)
    {
        TCPSocket->write(MessageArray);
        ShowResponseMessage(MessageArray);
    }

}

//0x10 更新寄存器数据
void Widget::UpdateRegistersData(quint16 BeginAddress, quint16 DataNumber, QString DataString)
{
    QString temp;
    int j=0;
    for(int i=0;i<DataNumber;i++)
    {
        while(j< DataString.size() && DataString[j] != ' ')
        {
            temp +=DataString[j];
            j++;
        }
        WriteData0X10(BeginAddress+i,temp);
        temp.clear();
        j++;
    }

}

//0x10功能码 写入寄存器数据
void Widget::WriteData0X10(int Column,QString registerData)
{
    //锁住写入寄存器数据信号，进行阻塞
    ui->registerTable->blockSignals(true);

    //更新ini文件数据
    settings->setValue("Section" + QString::number(Column + 1) + "/regi",registerData);

    //更新线圈数据表中数据
    ui->registerTable->setItem(1,Column,new QTableWidgetItem(registerData));

    //设置表格内文字水平+垂直对齐
    ui->registerTable->item(1,Column)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);

    //解锁写入寄存器数据信号
    ui->registerTable->blockSignals(false);
}

//0x01 0x03 生成正常响应报文 并调用报文发送函数
bool Widget::AnalysisMessageRead(QByteArray MessageArray)
{
    //异常分析
    //异常码、异常响应报文
    quint8 AbnormalFunctionCode;
    QByteArray AbnormalResponseMessage;
    //判断顺序：
    //查询报文长度是否非法
    if(MessageArray.size() != REQUEST_MESSAGE_LENGTH_Read)
    {
        ui->messageEdit->append("查询报文长度非法！");
        return false;
    }
    //获取数据起始地址和数量
    quint16 BeginAddress;
    BeginAddress = ((quint8)MessageArray[8] << 8) | (quint8)MessageArray[9];
    quint16 DataNumber;
    DataNumber = ((quint8)MessageArray[10] << 8) | (quint8)MessageArray[11];
    //查询报文数量是否合法
    switch(MessageArray.at(7))
    {
    case 1:
        if(DataNumber < READ_COIL_MINNUM || DataNumber > READ_COIL_MAXNUM)
        {
            //发送异常报文，异常码03
            AbnormalFunctionCode = 0x03;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            //异常提示
            ui->messageEdit->append("线圈查询数量非法,请求报文中数据查询数量超出查询范围！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        if((BeginAddress+DataNumber-1) > ADDRESS_MAX)
        {
            //发送异常报文，异常码02
            AbnormalFunctionCode = 0x02;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            ui->messageEdit->append("线圈查询非法,请求报文中起始地址后可读取的线圈数量小于查询数量！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }

        break;
    case 3:
        if(DataNumber < READ_REGISTER_MINNUM || DataNumber > READ_REGISTER_MAXNUM)
        {
            //发送异常报文，异常码03
            AbnormalFunctionCode = 0x03;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            ui->messageEdit->append("查询数量非法,请求报文中数据查询数量超出查询范围！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        if((BeginAddress+DataNumber-1) > ADDRESS_MAX)
        {
            //发送异常报文，异常02
            AbnormalFunctionCode = 0x02;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            ui->messageEdit->append("线圈查询非法,请求报文中起始地址后可读取的线圈数量小于查询数量！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        break;
    }

    //正常响应
    //获取查询数据
    QByteArray data;
    if(MessageArray.at(7) == 1)
    {
        data = GetData0X01(BeginAddress,DataNumber);
    }
    else if( MessageArray.at(7) == 3)
    {
        data = GetData0X03(BeginAddress,DataNumber);
    }
    //生成正常响应报文
    QByteArray res = NormalResponseMessageCreate(MessageArray,data);
    //发送响应报文
    NormalResponseMessageSend(res);
    return true;

}

//0x01 0x03 生成正常响应报文
QByteArray Widget::NormalResponseMessageCreate(QByteArray MessageArray,QByteArray DataArray)
{
    //MessageArray 接收到的字节数组
    QByteArray RespondeMessageArr;

    //响应报文总字节数
    quint16 RespondeMessageBytesNum;

    //2+2+2+1+1  即事务元标志符+协议标识符+（后续报文）长度+ 地址 + 功能码
    RespondeMessageBytesNum = 8 + 1 + (quint16)DataArray.size();
    quint16 length = RespondeMessageBytesNum - 6;
    RespondeMessageArr.resize(RespondeMessageBytesNum);

    //事务元标识符
    RespondeMessageArr[0]=MessageArray[0];
    RespondeMessageArr[1]=MessageArray[1];
    //协议地址
    RespondeMessageArr[2]=MessageArray[2];
    RespondeMessageArr[3]=MessageArray[3];
    //后续包长度
    RespondeMessageArr[4]= length>>8;
    RespondeMessageArr[5]= length & 0xff;
    //地址
    RespondeMessageArr[6]= MessageArray[6];
    //功能码
    RespondeMessageArr[7]=MessageArray[7];
    //数据长度
    RespondeMessageArr[8]= (quint8)DataArray.size();
    //数据
    for(int i=0;i < DataArray.size();i++)
    {
        RespondeMessageArr[i+9]=DataArray[i];
    }
    return RespondeMessageArr;
}

//0x0f 0x10 生成正常响应报文 并调用报文发送函数
bool Widget::AnalysisMessageWrite(QByteArray MessageArray)
{

    if(MessageArray.size() < TCP_MIN_LENGTH)
    {
        ui->messageEdit->append("请求报文长度错误！");
        return false;
    }
    quint8 AbnormalFunctionCode;
    QByteArray AbnormalResponseMessage;
    //判断顺序：
    //获取数据起始地址和数量
    quint16 BeginAddress;
    BeginAddress = ((quint8)MessageArray[8] << 8) | (quint8)MessageArray[9];
    quint16 DataNumber;
    DataNumber = ((quint8)MessageArray[10] << 8) | (quint8)MessageArray[11];
    //报文数量是否合法
    switch(MessageArray.at(7))
    {
    case 15:
        //写入数量
        if(DataNumber < WRITE_COIL_MINNUM || DataNumber > WRITE_COIL_MAXNUM)
        {
            //发送异常报文，异常码03
            AbnormalFunctionCode = 0x03;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            //异常提示
            ui->messageEdit->append("线圈写入数量非法,请求报文中数据写入数量超出写入范围！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        //起始地址+写入数量
        if((BeginAddress+DataNumber-1) > ADDRESS_MAX)
        {
            //发送异常报文，异常码02
            AbnormalFunctionCode = 0x02;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            ui->messageEdit->append("线圈写入非法,请求报文中起始地址后可写入的线圈数量小于写入数量！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        //字节字段 写入数量
        quint8 DataByteNumber;
        DataByteNumber = (quint8)MessageArray.at(12);
        if(DataByteNumber != (DataNumber+7)/8)
        {
            ui->messageEdit->append("线圈写入非法,请求报文中字节字段与写入数量所需要的字节不一致！");

            return false;
        }
        //数据项长度 字节字段
        if(DataByteNumber != (MessageArray.size() - 13))
        {

            ui->messageEdit->append("线圈写入非法,请求报文中数据字节字段与数据项实际字节长度不一致！");
            return false;
        }
        break;
    case 16:
        //写入数量
        if(DataNumber < WRITE_REGISTER_MINNUM || DataNumber > WRITE_REGISTER_MAXNUM)
        {
            //发送异常报文，异常码03
            AbnormalFunctionCode = 0x03;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            ui->messageEdit->append("寄存器写入数量非法,请求报文中数据写入数量超出写入范围！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        //起始地址 + 写入数量
        if((BeginAddress+DataNumber-1) > ADDRESS_MAX)
        {
            //发送异常报文，异常02
            AbnormalFunctionCode = 0x02;
            AbnormalResponseMessage = AbnormalMessageCreate(MessageArray,AbnormalFunctionCode);
            AbnormalMessageSend(AbnormalResponseMessage);
            ui->messageEdit->append("寄存器写入非法,请求报文中起始地址后可写入的寄存器数量小于写入数量！");
            ShowResponseMessage(AbnormalResponseMessage);
            return false;
        }
        //字节字段  写入数量
        quint16 ByteNumber;
        ByteNumber = (quint8)MessageArray[12];

        if((2*DataNumber) != ByteNumber)
        {

            ui->messageEdit->append("字节字段错误,请求报文中数据字节数与写入数量对应的字节数不一致！");

            return false;
        }
        //数据项长度 字节字段是否匹配
        quint8 RegistersByteNumber = MessageArray.size() - 13;
        if(RegistersByteNumber != (quint8)MessageArray[12])
        {

            ui->messageEdit->append("数据项字节错误,请求报文中数据项字节数与数据字节字段不一致！");

            return false;
        }
        break;
    }

    //正常报文响应
    //初始化响应报文
    QByteArray ResponseMessage;
    ResponseMessage.resize(REQUEST_MESSAGE_LENGTH_0X01_0X03); //正常报文长度
    for(int i=0;i<REQUEST_MESSAGE_LENGTH_0X01_0X03;i++)
    {
        ResponseMessage[i]=MessageArray[i];
    }
    ResponseMessage[4]=(quint8)0;
    ResponseMessage[5]=(quint8)6;

    //获取修改数据的地址
    quint16 ReceiveDataAddress;
    ReceiveDataAddress = ((quint8)MessageArray[8]<<8) | (quint8)MessageArray[9];
    //获取修改数据的数量
    quint16 ReceiveDataNumber;
    ReceiveDataNumber =((quint8)MessageArray[10]<<8) | (quint8)MessageArray[11];
    //获取修改数据的值
    QByteArray ReceiveData;
    ReceiveData.resize(MessageArray.size() - REQUEST_MESSAGE_LENGTH_0X01_0X03-1);
    for(int i =0;i<ReceiveData.size();i++ )
    {
        ReceiveData[i]=MessageArray[i+REQUEST_MESSAGE_LENGTH_0X01_0X03+1];
    }

    //数据写入
    QString res;
    switch(MessageArray.at(7))
    {
    case 15:
        //0x0f
        //显示写入的线圈值
        ui->messageEdit->append("----------------------Write in Coil----------------------");
        ui->messageEdit->append("线圈起始地址："+QString::number(BeginAddress)+"    "+"写入数量："+QString::number(ReceiveDataNumber));
        ShowCoilsData(ReceiveData,ReceiveDataNumber);
        ui->messageEdit->append("--------------------------------------------------------------");
        //线圈写入
        res = HexByteArrayToBinString(ReceiveData);
        UpdateCoilsData(ReceiveDataAddress,ReceiveDataNumber,res);
        break;
    case 16:
        //0x10 写多个寄存器
        //显示写入的寄存器值
        ui->messageEdit->append("----------------------Write in Register----------------------");
        ui->messageEdit->append("寄存器起始地址："+QString::number(BeginAddress)+"    "+"写入数量："+QString::number(ReceiveDataNumber));
        ShowRegisterData(ReceiveData);
        ui->messageEdit->append("------------------------------------------------------------------");

        //寄存器写入
        res = HexByteArrayToDecString(ReceiveData);
        UpdateRegistersData(ReceiveDataAddress,ReceiveDataNumber,res);
        break;
    }
    NormalResponseMessageSend(ResponseMessage);
    return true;
}

//更新线圈数据
void Widget::UpdateCoilsData(quint16 BeginAddress,quint16 DataNumber,QString DataString)
{

    for(int i=0;i<DataNumber;i++)
    {
        int Column = BeginAddress + i;
        QString coilData = DataString.at(i);
        WriteData0X0F(Column,coilData);
    }
}

//0x10功能码 将16进制字节数组转化为 10进制字符串，每个寄存器的10进制字符串用空格分隔
QString Widget::HexByteArrayToDecString(QByteArray DataArray)
{
    QString res;
    quint16 DataArrayLength = DataArray.size();
    for(int i = 0; i < DataArrayLength; i += 2)
    {
        res += QString::number(BondTwoUint8ToUint16((quint8)DataArray.at(i),(quint8)DataArray.at(i+1)));
        res +=" ";
    }
    return res;
}

//0x0f功能码 将16进制字节数组转化为 2进制字符串
QString Widget::HexByteArrayToBinString(QByteArray DataArray)
{
    //2进制字符串的长度
    quint16 DataArrayLength;
    DataArrayLength = DataArray.size();

    QString res;
    for(int i = 0; i < DataArrayLength; i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)DataArray.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        res += str;
    }
    return res;
}

//0x03功能码 获取寄存器数据
QByteArray Widget::GetData0X03(quint16 BeginAddress,quint16 Number)
{
    //声明读取的数据字符串
    QString getDataString;
    //声明响应报文字节数项
    quint8 responseMessageByteNum;

    //求响应报文字节数项，为请求报文数量项的两倍，一个寄存器两个字节
    responseMessageByteNum = Number*2;

    //声明线圈数据数组
    QByteArray registersDataArr;
    registersDataArr.resize(responseMessageByteNum);

    //从数据表中读取需要数量的寄存器数据,形成二进制形式字符串
    for(int i = 0; i < Number; i++)
    {
        //取出10进制字符串
        getDataString = ui->registerTable->item(1,(i + BeginAddress))->text();
        //转化为2进制字符串，不足补0，凑足16位
        getDataString  = QString("%1").arg((quint16)getDataString.toInt(NULL,10),16,2,QLatin1Char('0'));
        //前8位为一个字节
        registersDataArr[2*i] = getDataString.mid(0,8).toInt(NULL,2);
        //后8位为一个字节
        registersDataArr[2*i + 1] = getDataString.mid(8,8).toInt(NULL,2);
    }

    return registersDataArr;
}

void Widget::ShowCoilsData(QByteArray CoilsDataArray,quint16 ReceiveDataNumber)
{
    //取出需要写入的线圈值，并显示
    QString dataObtained;
    for(int i = 0; i < CoilsDataArray.size(); i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)CoilsDataArray.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        dataObtained += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    dataObtained = dataObtained.left(ReceiveDataNumber);

    //每个线圈用空格隔开
    QString res;
    for(int i=0;i<dataObtained.size();i++)
    {
        res += dataObtained[i];
        res += " ";
    }

    ui->messageEdit->append("线圈写入："+res);
}

void Widget::ShowRegisterData(QByteArray RegistersDataArray)
{

    //显示需要写入寄存器的值
    QString dataObtained;
    for(int i = 0; i < RegistersDataArray.size(); i += 2)
    {
        dataObtained += QString::number(BondTwoUint8ToUint16((quint8)RegistersDataArray.at(i),(quint8)RegistersDataArray.at(i+1)));
        dataObtained += " ";
    }
    ui->messageEdit->append("寄存器写入："+dataObtained);
}

//0x0f功能码 写入线圈数据
void Widget::WriteData0X0F(int Column,QString CoilData)
{
    //锁住写入线圈数据信号，进行阻塞
    ui->coilTable->blockSignals(true);

    //更新ini文件数据
    settings->setValue("Section" + QString::number(Column + 1) + "/coil",CoilData);
    //qDebug() << settings->value("Section" + QString::number(Column + 1) + "/coil").toString() << endl;

    //更新线圈数据表中数据
    if(CoilData == "1")
    {
        CoilData = "ON";
    }
    else
    {
        CoilData = "OFF";
    }
    ui->coilTable->setItem(1,Column,new QTableWidgetItem(CoilData));
    //设置表格内文字水平+垂直对齐
    ui->coilTable->item(1,Column)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);

    //解锁写入线圈数据信号
    ui->coilTable->blockSignals(false);
}
